#include <idt.h>
#include <sched.h>
#include <loader.h>
#include <string.h>

typedef struct str_sched_task {
	uint_32 state;
	uint_32 quantum;
	pid prev;
	pid next;
} sched_task;
sched_task tasks[MAX_PID + 1];

//tarea actual
static pid tasks_current = MAX_PID;

void sched_init(void) {
	memset( tasks, 0, sizeof(sched_task) * MAX_PID );
}

void sched_load(pid pd) {
	pid prev;
	
	//le doy un QUANTUM y la pongo como disponible
	tasks[pd].state = TASK_RUN;
	tasks[pd].quantum = QUANTUM_DEFAULT;
 
 	//la agrego a la lista
 	if (tasks_current == MAX_PID || tasks_current == IDLE_TASK) {
		//si no habia ninguna tarea a continuacion (la lista esta vacia)
		tasks[pd].prev = pd;
		tasks[pd].next = pd;
		tasks_current = pd;
	}
	else {
		//si habia elementos en la lista la agrego antes de la tarea actual
		prev = tasks[tasks_current].prev;
		tasks[pd].prev = prev;
		tasks[pd].next = tasks_current;
		tasks[tasks_current].prev = pd;
		tasks[prev].next = pd;
	}
}

void sched_unblock(pid pd) {
	pid prev;
	//cambio el estado
	tasks[pd].state = TASK_RUN;

	//la agrego a la lista
 	if (tasks_current == MAX_PID || tasks_current == IDLE_TASK) {
		//si no habia ninguna tarea a continuacion (la lista esta vacia)
		tasks[pd].prev = pd;
		tasks[pd].next = pd;
		tasks_current = pd;
	}
	else {
		//si habia elementos en la lista la agrego antes de la tarea actual
		prev = tasks[tasks_current].prev;
		tasks[pd].prev = prev;
		tasks[pd].next = tasks_current;
		tasks[tasks_current].prev = pd;
		tasks[prev].next = pd;
	}
}

int
sched_exit() {
	
	sched_task * current_task;
	pid prev, next;

	if (tasks_current == MAX_PID) {
		return MAX_PID;
	}

	current_task = &(tasks[tasks_current]);
	next = current_task->next;
	prev = current_task->prev;

	if (next == tasks_current) {
		//si solo esta en el la lista
		memset( current_task, 0, sizeof(sched_task) );
		tasks_current = IDLE_TASK;
	}
	else {
		//si hay mas elementos 
		tasks[prev].next = next;
		tasks[next].prev = prev;
		memset( current_task, 0, sizeof(sched_task) );
		tasks_current = next;
	}

	return tasks_current;
}

int
sched_block() {
	sched_task * current_task;
	pid prev, next;

	if (tasks_current == MAX_PID || tasks_current == IDLE_TASK) {
		return tasks_current;
	}

	current_task = &(tasks[tasks_current]);
	next = current_task->next;
	prev = current_task->prev;

	if (next == tasks_current) {
		//si solo esta en el la lista
		current_task->state = TASK_STOP;
		tasks_current = IDLE_TASK;
	}
	else {
		//si hay mas elementos 
		tasks[prev].next = next;
		tasks[next].prev = prev;
		current_task->state = TASK_STOP;
		tasks_current = next;
	}

	return tasks_current;
}

int
sched_tick() {

	//si la lista esta vacia devuelvo MAX_PID
	if (tasks_current == MAX_PID || tasks_current == IDLE_TASK) {
		return IDLE_TASK;
	}

	if (tasks[tasks_current].quantum > 0) {
		//si aun tiene quantum la dejo
		tasks[tasks_current].quantum--;
	}
	else {
		//si no tiene mas quantum salto a la siguiente tarea
		tasks[tasks_current].quantum = QUANTUM_DEFAULT;
		tasks_current = tasks[tasks_current].next;
	}

	return tasks_current;
}

